/**
 * 
 */
package com.upstairstechnology.oi.notification.email.resolver.perforce;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.mail.Address;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.upstairstechnology.oi.determination.CommandReader;
import com.upstairstechnology.oi.notification.email.resolver.AbstractEmailResolver;

/**
 * Email resolver for Perforce SCM.
 * 
 * @author Jeff Jensen
 */
public class EmailResolverPerforce extends AbstractEmailResolver {
    /** Logger instance. */
    private static final Logger LOGGER =
            LoggerFactory.getLogger(EmailResolverPerforce.class);

    /** Strategy to process output from the command console/process. */
    private CommandReader commandReader;

    /**
     * {@inheritDoc}
     */
    public Address getEmailAddress(String userId) throws AddressException,
            IOException {
        String addressStr = lookupEmailAddress(userId);
        if (addressStr == null) {
            final String msg = "User id '" + userId + "' not found";
            throw new IllegalArgumentException(msg);
        }
        Address address = new InternetAddress(addressStr);
        return address;
    }

    /**
     * Lookup the email address from Perforce for the specified user id.
     * 
     * @param userId
     *            The Perforce user id to get the email address for.
     * @return Email address for the specified user.
     * @throws IOException
     *             When processing command line output.
     */
    protected String lookupEmailAddress(String userId) throws IOException {
        String line = getLineWithEmailAddress(userId);
        if (line == null) {
            final String msg = "No line found with an email address";
            throw new IllegalStateException(msg);
        }
        String emailAddress = parseEmailAddress(line);
        return emailAddress;
    }

    /**
     * Get the Perforce output line with the email address on it.
     * 
     * @param userId
     *            SCM user id to lookup email address for.
     * @return Perforce output line with email address on it; null if no line
     *         found with email on it.
     * @throws IOException
     *             When errors occur executing the command. The environment
     *             variables are logged when this exception occurs.
     */
    protected String getLineWithEmailAddress(String userId) throws IOException {
        List<String> cmdList = new ArrayList<String>();
        cmdList.add("p4");
        cmdList.add("user");
        cmdList.add("-o");
        cmdList.add(userId);
        ProcessBuilder processBuilder = new ProcessBuilder(cmdList);

        Process process = null;
        try {
            process = processBuilder.start();
        } catch (IOException e) {
            logEnvironment(processBuilder);
            throw e;
        }

        BufferedReader inStd = commandReader.setupIn(process.getInputStream());
        BufferedReader inErr = commandReader.setupIn(process.getErrorStream());

        String lineStd = commandReader.readNextLine(cmdList, inStd, inErr);
        while (lineStd != null && !lineStd.startsWith("Email:")) {
            LOGGER.debug("lineStd={}", lineStd);
            lineStd = commandReader.readNextLine(cmdList, inStd, inErr);
        }

        return lineStd;
    }

    /**
     * Expecting a line formatted thusly: "Email: address@domain".
     * 
     * @param line
     *            Perforce output line to parse an email address from.
     * @return Email address.
     */
    protected String parseEmailAddress(String line) {
        LOGGER.debug("Line to parse={}", line);
        if (line == null) {
            final String msg = "line argument must not be null";
            throw new IllegalArgumentException(msg);
        }
        String[] lineElements = line.split(":");
        String emailElement = lineElements[1].trim();
        LOGGER.debug("Parsed email address={}", emailElement);

        return emailElement;
    }

    /**
     * Get the commandReader.
     * 
     * @see {@link commandReader}.
     * 
     * @return The commandReader.
     */
    public CommandReader getCommandReader() {
        return commandReader;
    }

    /**
     * Set the commandReader.
     * 
     * @see {@link commandReader}.
     * 
     * @param reader
     *            The commandReader to set.
     */
    public void setCommandReader(CommandReader reader) {
        this.commandReader = reader;
    }
}
